package org.monkey.common.generator.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.extra.compress.CompressUtil;
import java.io.File;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.monkey.common.constant.config.CommonConstant;
import org.monkey.common.constant.entity.DbConfig;
import org.monkey.common.constant.entity.MysqlColumnInfo;
import org.monkey.common.constant.exception.BaseException;
import org.monkey.common.constant.util.DataUtil;
import org.monkey.common.generator.entity.EntityConfig;
import org.monkey.common.generator.entity.GeneratorConfig;
import org.monkey.common.generator.entity.JavaEntityInfo;
import org.monkey.common.generator.service.GeneratorApiService;
import org.monkey.common.generator.service.TemplateFileFormatter;
import org.monkey.common.generator.util.MysqlUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class GeneratorApiServiceImpl implements GeneratorApiService {

  @Autowired
  private List<TemplateFileFormatter> templateFileFormatters;

  private static final String ZIP_CONTENT_TYPE = "application/x-zip-compressed";

  @Override
  public ResponseEntity<FileSystemResource> generator(GeneratorConfig config) {
    List<JavaEntityInfo> javaEntityInfos =
        getEntityInfos(
            config.getDbConfig(), config.getEntityConfigs(), config.getTablePre(), config.isHump());
    String uuid = UUID.randomUUID().toString().replace("-", "");
    File workDir = initWorkspace(uuid, config.getModuleName());
    for (TemplateFileFormatter tf : templateFileFormatters) {
      if (config.getTemplates().contains(tf.getTemplateName())) {
        tf.format(workDir, javaEntityInfos, config);
      }
    }
    File zipFile = FileUtil.file(workDir + "/" + config.getModuleName() + ".zip");
    CompressUtil.createArchiver(CharsetUtil.CHARSET_UTF_8, ArchiveStreamFactory.ZIP, zipFile)
        .add(FileUtil.file(workDir.getAbsolutePath() + "/" + config.getModuleName()))
        .finish()
        .close();
    String fileName = config.getModuleName() + ".zip";
    return createFileResponse(fileName, zipFile, ZIP_CONTENT_TYPE);

  }


  private File initWorkspace(String uuid, String moduleName) {
    // 生成目录结构
    String s = CommonConstant.CONSTANT_PATH + "/" + DateUtil.format(new Date(), "yyyy-MM-dd") + "/" + uuid + "/" + moduleName;
    File file = new File(s);
    if (!file.exists()) {
      file.mkdirs();
    }
    return file;
  }

  private List<JavaEntityInfo> getEntityInfos(
      DbConfig dbConfig, List<EntityConfig> entityConfigs, String tablePre, boolean hump) {
    List<JavaEntityInfo> javaEntityInfos = new ArrayList<>();
    if (dbConfig != null && DataUtil.isNotEmpty(entityConfigs)) {
      Connection connection1 = null;
      Connection connection2 = null;
      try {
        connection1 = MysqlUtil.getConnect(dbConfig);
        connection2 = MysqlUtil.getConnect(dbConfig);
        String database = MysqlUtil.getDateBase(connection1);
        for (EntityConfig entityConfig : entityConfigs) {
          String tableName = entityConfig.getTableName();
          List<MysqlColumnInfo> columnInfos = MysqlUtil.getColumns(connection2, database, tableName);
          JavaEntityInfo javaEntityInfo =
              new JavaEntityInfo(
                  tableName, hump, tablePre, entityConfig.getEntityDescription(), columnInfos);
          javaEntityInfos.add(javaEntityInfo);
        }
      } catch (Exception e) {
        log.error("sql connect or execute failed:", e);
        throw new BaseException(e);
      } finally {
        MysqlUtil.close(connection1, connection2);
      }
    }
    return javaEntityInfos;
  }

  private ResponseEntity<FileSystemResource> createFileResponse(String fileName, File file, String contentType) {
    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
    headers.add(HttpHeaders.PRAGMA, "no-cache");
    headers.add(HttpHeaders.EXPIRES, "0");
    headers.add(HttpHeaders.LAST_MODIFIED, new Date().toString());
    headers.add(HttpHeaders.ETAG, String.valueOf(System.currentTimeMillis()));
    return ResponseEntity.ok()
        .headers(headers)
        .contentLength(file.length())
        .contentType(MediaType.parseMediaType(contentType))
        .body(new FileSystemResource(file));
  }
}
